from pmapi import log
from pmapi import lock
from pmapi import git
from pmapi import utils
import sys
import os
import shutil
import sqlite3
import json
import platform
import time
import signal

PACKAGE_PATH = f"{utils.find_disk()}\\" + \
    "PEinjector\\package".replace('\\', os.sep)

exit_flag = False


def read_exit(*args, **kwargs):
    global exit_flag
    sys.stdout.write("\nPressed Ctrl+C, Will Exit...\n\n")
    exit_flag = True


def act_pkg(pkg_name: str) -> None:  # 执行软件包（仅在 PE 下）
    if platform.system() == 'Windows' and os.path.exists("X:\\PEinjector"):
        log.info("hot load package")
        # TODO


def install(pkg_name: str, wait_user: bool = False, reinstall: bool = True, fix_inst: bool = False, progress_callback=lambda **kwargs: None) -> int:
    lockn = lock.Lock("install")  # 加锁
    log.info("install"+" "+pkg_name)
    remove_pkg_flag = False
    if pkg_name in os.listdir(PACKAGE_PATH):  # 重新安装软件包
        if reinstall is None:  # 未定义行为，用户输入
            user_input = input("Package installed. Reinstall? [y/N]")
            if user_input not in ("y", "Y", "a", "A"):
                sys.stdout.write("Abort.")
                lockn.remove()
                return 1
            else:
                log.warn("reinstall package: "+pkg_name)
                remove_pkg_flag = True
        if reinstall:  # 明确指定重新安装
            log.warn("reinstall package: "+pkg_name)
            remove_pkg_flag = True
        else:
            log.err("package \""+pkg_name+"\" installed")
            lockn.remove()
            return 2
    if wait_user:  # 询问用户输入
        user_input = input("Install? [Y/n]")
        if user_input not in ("y", "Y", "a", "A", ""):
            sys.stdout.write("Abort.")
            lockn.remove()
            return 1
    signal.signal(signal.SIGINT, read_exit)

    def install_pkg(pkg_name: str, remove: bool) -> None:
        global exit_flag
        if exit_flag:
            print("Exit!")
            lockn.remove()
            return -1

        def find_repo(pkg_name: str) -> str:  # thank for chatglm
            # 连接到SQLite数据库
            conn = sqlite3.connect(utils.get_builtin_dir(
                "database")+"/"+"database.db")
            cursor = conn.cursor()
            try:
                cursor.execute(
                    "SELECT repo FROM sources WHERE name=?", (pkg_name,))
                row = cursor.fetchone()  # 获取查询结果的第一行
                if row:
                    return row[0]  # 如果有结果，返回repo的值
                else:
                    return ""  # 如果没有找到，返回空字符串
            finally:
                # 关闭游标和连接
                cursor.close()
                conn.close()
        repo = find_repo(pkg_name)
        if repo == "":
            log.err(f"connot find package: \"{pkg_name}\"")
            return 3
        if os.path.exists(PACKAGE_PATH+os.sep+pkg_name):
            if remove:  # 允许删除
                sys.stdout.write("Remove "+PACKAGE_PATH+os.sep+pkg_name+"\n")
                # 已知shutil在删除 .git 时会出现权限问题
                # 当出现问题时尝试使用系统命令
                try:
                    shutil.rmtree(PACKAGE_PATH+os.sep+pkg_name)
                except:  # 降级命令
                    if platform.system() == "Windows":
                        retr = os.system(
                            "RMDIR /S /Q "+PACKAGE_PATH.replace("/", "\\")+os.sep+pkg_name+" >nul")
                    else:
                        retr = os.system(
                            "rm -rf "+PACKAGE_PATH.replace("\\", "/")+os.sep+pkg_name+" >/dev/null")
                    if retr != 0:
                        return 5
            else:
                sys.stdout.write("Pass "+pkg_name)
                return 0

        retg = git.clone(repo, PACKAGE_PATH+os.sep +
                         # 下载包
                         pkg_name, progress_callback=progress_callback, progress_callback_args={"pkgname": pkg_name})
        if exit_flag:
            print("Exit!")
            lockn.remove()
            return -1
        if retg != 0:
            log.err(f"clone \"{pkg_name}\" failed")
        for i in range(5):
            time.sleep(3)  # 很迷惑的sleep，不然找不到manifest
            if os.path.exists(PACKAGE_PATH+os.sep+pkg_name+os.sep+"manifest.json"):
                break
        else:
            log.err(f"repo \"{pkg_name}\" is not a package")
            return 3
        time.sleep(1)
        try:
            with open(PACKAGE_PATH+os.sep+pkg_name+os.sep+"manifest.json", "r", encoding="utf-8") as file:
                file_json = json.load(file)
        except:
            log.err(f"read \"{pkg_name}\" json failed")
            return 4
        if "dependence" in file_json:  # 检测依赖
            for i in file_json["dependence"]:
                log.info(f"install \"{i}\" from {pkg_name}")
                ret = install_pkg(i, fix_inst)  # 递归安装依赖
                if (ret != 0):  # 某个依赖出错
                    return ret
        return 0
    ret = install_pkg(pkg_name, remove_pkg_flag)
    lockn.remove()
    if ret != 0:
        return ret
    act_pkg(pkg_name)
    return 0
